<html>
<head>
<style id='page-skin-1' type='text/css'><!--

body {
background:#bca;
}

pre,code,strike {
color: #446;
background-color: #FFFFFF;
margin: 3px 18px 3px 8px !important;
padding: 3px 3px 3px 10px !important;
border-width: 3px;
border-style: inset;
}

/* Syntax highlighter */
.dp-highlighter
{
font-family: "Consolas", "Monaco", "Courier New", Courier, monospace;
font-size: 12px;
background-color: #E7E5DC;
width: 99%;
overflow: auto;
margin: 18px 0 18px 0 !important;
padding-top: 1px; /* adds a little border on top when controls are hidden */
}
/* clear styles */
.dp-highlighter ol,
.dp-highlighter ol li,
.dp-highlighter ol li span
{
margin: 0;
padding: 0;
border: none;
}
.dp-highlighter a,
.dp-highlighter a:hover
{
background: none;
border: none;
padding: 0;
margin: 0;
}
.dp-highlighter .bar
{
padding-left: 45px;
}
.dp-highlighter.collapsed .bar,
.dp-highlighter.nogutter .bar
{
padding-left: 0px;
}
.dp-highlighter ol
{
list-style: decimal; /* for ie */
background-color: #fff;
margin: 0px 0px 1px 45px !important; /* 1px bottom margin seems to fix occasional Firefox scrolling */
padding: 0px;
color: #5C5C5C;
}
.dp-highlighter.nogutter ol,
.dp-highlighter.nogutter ol li
{
list-style: none !important;
margin-left: 0px !important;
}
.dp-highlighter ol li,
.dp-highlighter .columns div
{
list-style: decimal-leading-zero; /* better look for others, override cascade from OL */
list-style-position: outside !important;
border-left: 3px solid #6CE26C;
background-color: #F8F8F8;
color: #5C5C5C;
padding: 0 3px 0 10px !important;
margin: 0 !important;
line-height: 14px;
}
.dp-highlighter.nogutter ol li,
.dp-highlighter.nogutter .columns div
{
border: 0;
}
.dp-highlighter .columns
{
background-color: #F8F8F8;
color: gray;
overflow: hidden;
width: 100%;
}
.dp-highlighter .columns div
{
padding-bottom: 5px;
}
.dp-highlighter ol li.alt
{
background-color: #FFF;
color: inherit;
}
.dp-highlighter ol li span
{
color: black;
background-color: inherit;
}
/* Adjust some properties when collapsed */
.dp-highlighter.collapsed ol
{
margin: 0px;
}
.dp-highlighter.collapsed ol li
{
display: none;
}
/* Additional modifications when in print-view */
.dp-highlighter.printing
{
border: none;
}
.dp-highlighter.printing .tools
{
display: none !important;
}
.dp-highlighter.printing li
{
display: list-item !important;
}
/* Styles for the tools */
.dp-highlighter .tools
{
padding: 3px 8px 3px 10px;
font: 9px Verdana, Geneva, Arial, Helvetica, sans-serif;
color: silver;
background-color: #f8f8f8;
padding-bottom: 10px;
border-left: 3px solid #6CE26C;
}
.dp-highlighter.nogutter .tools
{
border-left: 0;
}
.dp-highlighter.collapsed .tools
{
border-bottom: 0;
}
.dp-highlighter .tools a
{
font-size: 9px;
color: #a0a0a0;
background-color: inherit;
text-decoration: none;
margin-right: 10px;
}
.dp-highlighter .tools a:hover
{
color: red;
background-color: inherit;
text-decoration: underline;
}
/* About dialog styles */
.dp-about { background-color: #fff; color: #333; margin: 0px; padding: 0px; }
.dp-about table { width: 100%; height: 100%; font-size: 11px; font-family: Tahoma, Verdana, Arial, sans-serif !important; }
.dp-about td { padding: 10px; vertical-align: top; }
.dp-about .copy { border-bottom: 1px solid #ACA899; height: 95%; }
.dp-about .title { color: red; background-color: inherit; font-weight: bold; }
.dp-about .para { margin: 0 0 4px 0; }
.dp-about .footer { background-color: #ECEADB; color: #333; border-top: 1px solid #fff; text-align: right; }
.dp-about .close { font-size: 11px; font-family: Tahoma, Verdana, Arial, sans-serif !important; background-color: #ECEADB; color: #333; width: 60px; height: 22px; }
/* Language specific styles */
.dp-highlighter .comment, .dp-highlighter .comments { color: #008200; background-color: inherit; }
.dp-highlighter .string { color: blue; background-color: inherit; }
.dp-highlighter .keyword { color: #069; font-weight: bold; background-color: inherit; }
.dp-highlighter .preprocessor { color: gray; background-color: inherit; }
/* Syntax highlighter */
 
--></style> 
<!-- Add-in CSS for syntax highlighting --> 
<script src='http://syntaxhighlighter.googlecode.com/svn/trunk/Scripts/shCore.js' type='text/javascript'></script> 
<script src='http://syntaxhighlighter.googlecode.com/svn/trunk/Scripts/shBrushJava.js' type='text/javascript'></script> 
</head>
<body>

<div>
Apache Camel is a routing and mediation engine which implements the 
<a href="http://www.enterpriseintegrationpatterns.com/toc.html">Enterprise Integration Patterns</a>.
</div>
<div>
Sounds real heavy? Not really. Camel is designed to be really light weight and has a small footprint.
So it can be reused anywhere, whether in a servlet, in a Web services stack, inside a full ESB or a 
standalone messaging application.
</div>
<div>
If you have prior concept on EIP, you should have little difficult to pick up Camel. 
Having said that, Camel is easy to learn but take some effort to master.
</div>
<div>
In the following, I'm going to demonstrate how easy it is to implement Camel based messaging application. 
In order to make it easier to follow along, I'm going to use <a href="http://groovy.codehaus.org/Groovy+Shell">Groovy Shell</a> to run the Groovy scripts 
in this tutorial. Groovy is much more expressive without all the noise of typical Java code. 
Also each of the scripts in this tutorial is contain in a single source file, which no more than a couple dozen of lines.
</div>
<h3>Kick Camel</h3>
<div>
Let first create a simple script to illustrate how to define routes and start the Camel kicking. 
Save the following into a file named <a href="http://crank-on-struts.googlecode.com/svn/groovy-camel/src/KickCamel.groovy">KickCamel.groovy</a>.
<textarea name="code" class="java">
import groovy.grape.Grape
Grape.grab(group:"org.apache.camel", module:"camel-core", version:"2.0.0")

class MyRouteBuilder extends org.apache.camel.builder.RouteBuilder {
  void configure() {
    from("seda://foo").to("mock://result")
  }
}
mrb = new MyRouteBuilder()
ctx = new org.apache.camel.impl.DefaultCamelContext()
ctx.addRoutes mrb
ctx.start()
p = ctx.createProducerTemplate()
p.sendBody("seda:foo", "Camel Ride for beginner")
e = ctx.getEndpoints("mock://result")[0]
ex = e.exchanges[0]
println "INFO> ${ex} in.body=${ex.in.body} correlationId=${ex.properties['CamelCorrelationId']}"
</textarea></div>

<div>
Next start the Groovy Shell and load the file:
</div>

<pre>
$ groovysh
groovy:000> load kickCamel.groovy
</pre>
If all went well, you should see a bunch of output and then the output from the script:
<pre>
INFO> Exchange[Message: Camel Ride for beginner]
===> null
groovy:000>
</pre>
<div>Now the Groovy Shell is ready to accept further commands. Try the following:
<pre>
groovy:000> ctx.routes
===> [EventDrivenConsumerRoute[Endpoint[seda://foo] -> UnitOfWork(Channel[sendTo(Endpoint[mock://result])])]]
</pre>
As you can see, you can explore the Camel objects. Here is a sample session:
<pre>
groovy:000> ctx.components
===> {mock=org.apache.camel.component.mock.MockComponent@14f2bd7, seda=org.apache.camel.component.seda.SedaComponent@c759f5}
groovy:000> ctx.endpoints
===> [Endpoint[seda://foo], Endpoint[mock://result]]
groovy:000> ctx.endpoints[1].exchanges
===> [Exchange[Message: Camel Ride for beginner]]
groovy:000> ctx.endpoints[1].exchanges[0].in.body
===> Camel Ride for beginner
groovy:000> p.sendBody("seda:foo", "Camel Kicking")
===> null
groovy:000> e.exchanges                        
===> [Exchange[Message: Camel Ride for beginner], Exchange[Message: Camel Kicking]]
</pre>
</div>
<div>
So what have we got? First we use <a href="http://groovy.codehaus.org/Grape">Grape.grab(..)</a> to pull in Camel. 
For this simple example, we only need <em>camel-core</em>. 
Some of the common components are already included in the <em>camel-core</em>. 
Next we extends <a href="http://camel.apache.org/maven/camel-core/apidocs/org/apache/camel/builder/RouteBuilder.html">
RouteBuilder</a> to configure a simple route definition. Here, we are using the 
<a href="http://camel.apache.org/dsl.html">Camel Java DSL</a> to express the route.
</div>
<div>
Our route simply wires together a <a href="http://camel.apache.org/seda.html">SEDA</a> endpoint ("seda:foo") and a 
<a href="http://camel.apache.org/mock.html">MOCK</a> endpoint ("mock:result:"). Note that we simply 
specify the URI of the endpoints and Camel is smart enough to figure out the underlying Components.
Then we instantiate the <a href="http://camel.apache.org/maven/camel-core/apidocs/org/apache/camel/CamelContext.html">
CamelContext</a> and tell it to include our routeBuilder.
</div>
<div>
To actually do something, we obtain a <a href="http://camel.apache.org/producertemplate.html">ProducerTemplate</a>
 and uses it send to the <em>seda:foo</em> endpoint. 
That causes Camel to create an <a href="http://camel.apache.org/exchange.html">Exchange</a> 
and excute the route processing. 
For our simple route, the exchange/message simply end up on the mock:result 
endpoint.
</div>
<div>
Finally our script just display the exchange from the mock:result endpoint.
</div>
<h3>Hello Camel</h3>
Now let us make the script a bit more interesting. Let add some processing logic. 
We will create/extends a <a href="http://camel.apache.org/processor.html">Processor</a> and 
insert it into our simple route. Save the following to a file named 
<a href="http://crank-on-struts.googlecode.com/svn/groovy-camel/src/HelloCamel.groovy">HelloCamel.groovy</a>.

<pre name="camelHello" class="java">
import groovy.grape.Grape
Grape.grab(group:"org.apache.camel", module:"camel-core", version:"2.0.0")

class HelloProcessor implements org.apache.camel.Processor {
  void process(org.apache.camel.Exchange exchange) {
    exchange.in.body = "Hello ${exchange.in.body}, nice going."
  }
}

class MyRouteBuilder extends org.apache.camel.builder.RouteBuilder {
  void configure() {
    from("direct://foo").process(new HelloProcessor()).to("mock://result")
  }
}

ctx = new org.apache.camel.impl.DefaultCamelContext()
mrb = new MyRouteBuilder()
ctx.addRoutes mrb
ctx.start()
p = ctx.createProducerTemplate()

p.sendBody("direct:foo", "Jack")

e = ctx.getEndpoints("mock://result")[0]
e.exchanges.each { ex ->
  println "INFO> in.body='${ex.in.body}'"
}
</pre>

Note that all we did here is to implement our Hello logic and insert it to our route.
<pre>
[jack@localhost src]$ groovysh 
Groovy Shell (1.6.6, JVM: 1.6.0_11)
Type 'help' or '\h' for help.
------------------------------------------------------------------------------------------------------------------------------------------
groovy:000> load HelloCamel.groovy
.........
INFO> in.body='Hello Jack, nice going.'
===> [Exchange[Message: Hello Jack, nice going.]]
groovy:000> 
</pre>
So this is more like a pipeline. Try sending another message to ensure that the Processor is doing something:
<pre>
groovy:000> p.sendBody("direct:foo", "Mary")
===> null
groovy:000> e.exchanges                     
===> [Exchange[Message: Hello Jack, nice going.], Exchange[Message: Hello Mary, nice going.]]
</pre>

<h3>Hello Camel, Bean style</h3>
The previous example is a no sweater, but we are tying our logic to Camel api. 
So let us implement out logic with a simple Java Bean. Save the following to a file named
<a href="http://crank-on-struts.googlecode.com/svn/groovy-camel/src/HelloBeanCamel.groovy">HelloBeanCamel.groovy</a>

<pre name="helloBean" class="java">
import groovy.grape.Grape
Grape.grab(group:"org.apache.camel", module:"camel-core", version:"2.0.0")

class HelloBean {
  public String sayHello(String body) {
    "Hello ${body}, nice going."
  }
  public String sayHelloToBoss(String body) {
    "Hello Boss."
  }
}

class MyRouteBuilder extends org.apache.camel.builder.RouteBuilder { 
  void configure() { 
    from("direct://foo").choice()
      .when(body().contains("Jack")).bean(HelloBean.class, "sayHelloToBoss")
      .otherwise().bean(HelloBean.class, "sayHello")
      .end().to("mock://result")
  }
}

ctx = new org.apache.camel.impl.DefaultCamelContext()
mrb = new MyRouteBuilder()
ctx.addRoutes mrb
ctx.start()
p = ctx.createProducerTemplate()

p.sendBody("direct:foo", "Jack")
p.sendBody("direct:foo", "Peter")

e = ctx.getEndpoints("mock://result")[0]
e.exchanges.each { ex ->
  println "INFO> in.body='${ex.in.body}'"
}
</pre>
<div>
Here we have replaced the Processor with a simple POJO, and provided two ways to say hello.
It is a snap to hook up our pojo to route using 
<a href="http://camel.apache.org/bean-binding.html">Camel Bean Binding</a>.
</div>
<div>
I have also added a <a href="http://camel.apache.org/content-based-router.html">Content Based Router</a> to
make this example a little more interesting. When the body of the message contains the string "Jack", we 
want to call the sayHelloToBoss method; otherwise call the sayHello method.
</div> 
<div>
Notice that the route DSL almost read like plain English?
</div>
<pre>
[jack@localhost src]$ groovysh 
groovy:000> load HelloBeanCamel.groovy  
...........
INFO> in.body='Hello Boss.'
INFO> in.body='Hello Peter, nice going.'
===> [Exchange[Message: Hello Boss.], Exchange[Message: Hello Peter, nice going.]]
</pre>

<h3>Multi-Channel, Multi-Format Hello World</h3>
<div>
A common situation in enterprise integration is that applications have different data format 
as well as communication channels. In this final example, I'm going to expose our Hello World
to the world and also to accept XML data requests.
</div>
<div>
Save the following to a file named
<a href="http://crank-on-struts.googlecode.com/svn/groovy-camel/src/MFMCHelloCamel.groovy">MFMCHelloCamel.groovy</a>
</div> 
<pre name="mFMChello" class="java">
import groovy.grape.Grape
Grape.grab(group:"org.apache.camel", module:"camel-core", version:"2.0.0")
Grape.grab(group:"org.apache.camel", module:"camel-jetty", version:"2.0.0")
Grape.grab(group:"org.apache.camel", module:"camel-freemarker", version:"2.0.0")

class HelloBean {
  public String sayHello(String name) {
    "Hello ${name}, nice going."
  }
  public String sayHelloToBoss(String name) {
    "Hello Boss."
  }
}

class MyRouteBuilder extends org.apache.camel.builder.RouteBuilder { 
  void configure() { 
    from("direct://foo").choice()
      .when(body().contains("Jack")).bean(HelloBean.class, "sayHelloToBoss")
      .otherwise().bean(HelloBean.class, "sayHello")
      .end().to("mock://result")
    from("direct://xmlfoo").transform().xpath("//user/@name", String.class).to("direct://foo")
	//curl -v -d "name=Mary&age=28" http://localhost:8080/tutorial
    from('jetty:http://localhost:8080/tutorial').transform()
	  .simple('<user name="${header.name}"><age>${header.age}</age></user>').to("direct://xmlfoo")
          .to("freemarker:hello.ftl")	
  }
}

ctx = new org.apache.camel.impl.DefaultCamelContext()
mrb = new MyRouteBuilder()
ctx.addRoutes mrb
ctx.start()
p = ctx.createProducerTemplate()

p.sendBody("direct:foo", "Jack")
p.sendBody("direct:xmlfoo", "<user name='Paul'><age>45</age></user>")
p.sendBody("direct:xmlfoo", "<user name='Jack'><age>42</age></user>")

e = ctx.getEndpoints("mock://result")[0]
e.exchanges.each { ex ->
  println "INFO> in.body='${ex.in.body}'"
}
</pre>

And the following to a file named
<a href="http://crank-on-struts.googlecode.com/svn/groovy-camel/src/hello.ftl">hello.ftl</a> 
<pre>
&lt;html&gt;
&lt;head&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;em&gt;${body}&lt;/em&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
<div>
What have I done here? 
<ul>
<li>Add a route <em>direct:xmlfoo</em> that expects XML formatted message. 
Using <a href="http://camel.apache.org/xpath.html">Camel XPath Transform</a>, the <em>name</em> attribute
is extracted from the input message and pass on to our original route <em>direct:foo</em> 
</li>
<li>Add another route <em>jetty:http://localhost:8080/tutorial</em> to expose our Hello service to the world.
<a href="http://camel.apache.org/simple.html">Simple Expression Language</a> is used here to transform the 
form request to XML and pass on to the <em>direct:xmlfoo</em> endpoint. Also notice that I <em>grab</em>
the <em>camel-jetty</em> and the <em>camel-freemarker</em> components. 
I have used Freemarker to wrap the result into html. 
The <a href="http://camel.apache.org/jetty.html">Camel Jetty</a> component is descripbe 
<a href="http://camel.apache.org/jetty.html">here</a>.
</li>
<li>For testing the multi-format features, the script send messages to both the <em>direct:foo</em> and
<em>direct:xmlfoo</em>.
</li>
<li>
One way to test the http channel is to use the <em>curl</em> 
command: <code>curl -v -d "name=Mary&age=28" http://localhost:8080/tutorial</code> 
</li>
</ul>
</div>
<pre>
[jack@localhost src]$ groovysh 
groovy:000> load MFMCHelloCamel.groovy
.................
INFO> in.body='Hello Boss.'
INFO> in.body='Hello Paul, nice going.'
INFO> in.body='Hello Boss.'
</pre>
Now in another command window:
<pre>
[jack@localhost tmp]$ curl -d "name=Mary&age=22" http://localhost:8080/tutorial
&lt;html&gt;
&lt;head&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;em&gt;Hello Mary, nice going.&lt;/em&gt;
&lt;/body&gt;
&lt;/html&gt;
[jack@localhost tmp]$ curl -d "name=Jack&age=28" http://localhost:8080/tutorial
&lt;html&gt;
&lt;head&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;em&gt;Hello Boss.&lt;/em&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
Back in the groovy shell:
<pre>
groovy:000> e.exchanges[-2..-1]
===> [Exchange[Message: Hello Mary, nice going.], Exchange[Message: Hello Boss.]]
</pre>

<h3>Summary</h3>
<div>
In the spirit of Development 2.0 : Doing more with less, much less, we have create a
Multi-Channel, Multi-Formatted application with a few dozen lines of code. The business logic is
implemented using a simple POJO with is not clobbered with enterprise concerns. 
</div>
<div>
If you need persistence support, just add camel-jpa. If you need monitoring, add 
<a href="http://camel.apache.org/bam.html">camel-bam</a>.
HA and scalability? Try <a href="http://svn.terracotta.org/svn/forge/projects/tim-camel">tim-camel</a>.
Other interesting components include: <a href="http://camel.apache.org/esper.html">camel-esper</a>
for Complex Eventing Processing and consuming Restful services with 
<a href="http://camel.apache.org/cxfrs.html">camel-cxfrs</a>.
</div>
<div>
 If only it is as simple as that, we are in heaven. 
</div>

<!-- Add-in Script for syntax highlighting --> 
<script language='javascript'>  
dp.SyntaxHighlighter.BloggerMode();  
dp.SyntaxHighlighter.HighlightAll('code');
dp.SyntaxHighlighter.HighlightAll('camelHello');
dp.SyntaxHighlighter.HighlightAll('helloBean');
dp.SyntaxHighlighter.HighlightAll('mFMChello');
</script> 
</body>
</html>

